home *** CD-ROM | disk | FTP | other *** search
/ Windows News 2005 February / WN_129_CD.iso / Windows / Extensions Firefox / FlashGot / flashgot-0.5.3.xpi / components / flashgotService.js
Encoding:
JavaScript  |  2004-11-14  |  39.7 KB  |  1,332 lines

  1. /***** BEGIN LICENSE BLOCK *****
  2.    - Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.    -
  4.    - The contents of this file are subject to the Mozilla Public License Version
  5.    - 1.1 (the "License"); you may not use this file except in compliance with
  6.    - the License. You may obtain a copy of the License at
  7.    - http://www.mozilla.org/MPL/
  8.    -
  9.    - Software distributed under the License is distributed on an "AS IS" basis,
  10.    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.    - for the specific language governing rights and limitations under the
  12.    - License.
  13.    -
  14.    - The Original Code is "FlashGot".
  15.    -
  16.    - The Initial Developer of the Original Code is Giorgio Maone.
  17.    - Portions created by the Initial Developer are Copyright (C) 2004
  18.    - the Initial Developer. All Rights Reserved.
  19.    -
  20.    - Contributor(s): Giorgio Maone <g.maone @ informaction.com>
  21.    -
  22.    - Alternatively, the contents of this file may be used under the terms of
  23.    - either the GNU General Public License Version 2 or later (the "GPL"), or
  24.    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  25.    - in which case the provisions of the GPL or the LGPL are applicable instead
  26.    - of those above. If you wish to allow use of your version of this file only
  27.    - under the terms of either the GPL or the LGPL, and not to allow others to
  28.    - use your version of this file under the terms of the MPL, indicate your
  29.    - decision by deleting the provisions above and replace them with the notice
  30.    - and other provisions required by the LGPL or the GPL. If you do not delete
  31.    - the provisions above, a recipient may use your version of this file under
  32.    - the terms of any one of the MPL, the GPL or the LGPL.
  33.    -
  34.    - ***** END LICENSE BLOCK *****/
  35.  
  36.  
  37.  
  38.  
  39. function FlashGotDM(name) {
  40.   if(arguments.length>0) {
  41.     this._init(name);
  42.   }
  43. }
  44.  
  45. FlashGotDM.dms=[];
  46. FlashGotDM.dmtests={};
  47. FlashGotDM.executables={};
  48.  
  49. FlashGotDM.prototype = {
  50.   _init: function(name) {
  51.     this.name=name;
  52.     const dms=FlashGotDM.dms;
  53.     dms[name]=dms[dms.length]=this;
  54.   }
  55. ,
  56.   _service: null,
  57.   _cookieManager: null,
  58.   _exeFile: false,
  59.   _supported: null
  60. ,
  61.   exeName: "FlashGot.exe",
  62.   askPath: [false,false,false]
  63. ,
  64.   get service() {
  65.     return this._service?this._service:this._service=
  66.     Components.classes["@informaction.org/flashgot-service;1"
  67.       ].getService(Components.interfaces.nsISupports).wrappedJSObject;
  68.   }
  69. ,
  70.   get cookieManager() {
  71.     return this._cookieManager?this._cookieManager:this._cookieManager=
  72.       Components.classes["@mozilla.org/cookiemanager;1"
  73.         ].getService(Components.interfaces.nsICookieManager);
  74.   }
  75. ,
  76.   get exeFile() {
  77.     if(typeof(this._exeFile)=="object") return this._exeFile;
  78.     const exeName=this.exeName;
  79.     if(!exeName) return this._exeFile=null;
  80.     if(typeof(FlashGotDM.executables[exeName])=="object") {
  81.       return this._exeFile=FlashGotDM.executables[exeName];
  82.     }
  83.     const exeFile=Components.classes["@mozilla.org/file/local;1"].createInstance(
  84.       Components.interfaces.nsILocalFile);
  85.     exeFile.initWithPath(this.service.globals.profDir.path);
  86.     exeFile.append(exeName);
  87.     try { exeFile.remove(true); } catch(ex) {}
  88.     this._exeFile=this.checkExePlatform(exeFile);
  89.     if(this._exeFile!=null) {
  90.       try {
  91.         this.createExecutable();
  92.         this.log(this._exeFile.path+" created");
  93.       } catch(ex) {
  94.         this._exeFile=null;
  95.       }
  96.     }
  97.     return FlashGotDM.executables[exeName]=this._exeFile;
  98.   }
  99. ,
  100.   checkExePlatform: function(exeFile) {
  101.     return /(\/.*\.exe$)|(\\.*\.sh)/i.test(exeFile.path)?null:exeFile;
  102.   }
  103. ,
  104.   get supported() {
  105.     if(typeof(this._supported)=="boolean") return this._supported;
  106.     if(!this.exeName) return true;
  107.     if(!this.exeFile) return false;
  108.     
  109.     var dmtest;
  110.     if(typeof(FlashGotDM.dmtests[this.exeName])!="string") {
  111.       const dmtestFile=this.service.tmpDir.clone();
  112.       dmtestFile.append(this.exeName+".test");
  113.       try {
  114.         this.launchSupportTest(dmtestFile);
  115.         this.log(dmtest=this.service.readFile(dmtestFile)); 
  116.       } catch(ex) {
  117.         this.log(ex.message);
  118.         dmtest="";
  119.       }
  120.       FlashGotDM.dmtests[this.exeName]=dmtest;
  121.     } else dmtest=FlashGotDM.dmtests[this.exeName];
  122.     return this._supported=new RegExp("^"+this.name+"\\|OK$","m").test(dmtest);
  123.   }
  124. ,
  125.   launchSupportTest: function (testFile) {
  126.     this.runNative(["-o",testFile.path],true);
  127.   }
  128. ,
  129.   log: function(msg) {
  130.     this.service.log(msg);
  131.   }
  132. ,
  133.   createJobHeader: function(links, opType) {
  134.     return links.length+";"+this.name+";"+opType+";"+links.folder+";\n"
  135.   }
  136. ,
  137.   createJobBody: function(links) {
  138.     var job="";
  139.     var l,url;
  140.     var cookies={};
  141.     for(var j=0, len=links.length; j<len; j++) {
  142.       job+="\n"+(url=(l=links[j]).href)+"\n"
  143.       +l._description+"\n"
  144.       +this.getCookie(url,cookies)+"\n"
  145.       +this.getPostData(l);
  146.     }
  147.     return job;
  148.   }
  149. ,
  150.   createJob: function(links,opType) {
  151.     return this.createJobHeader(links,opType) 
  152.     + this.getReferrer(links)
  153.     + this.createJobBody(links);
  154.   }
  155. ,
  156.   download: function(links, opType) {
  157.     links.folder=(links.length>0)?this.selectFolder(opType):""; 
  158.     try {
  159.       this.performJob(this.createJob(links,opType));
  160.     } catch(ex) {
  161.       this.log(ex);
  162.     }
  163.   }
  164. ,
  165.   getReferrer: function(links) {
  166.     return links.referrer?links.referrer
  167.       :links.document?links.document.location.href
  168.       :links[0]?links[0].href:"about:blank";
  169.   }
  170. ,
  171.   getCookie: function(url,cookies) {
  172.     
  173.     const parts=url.match(/http[s]{0,1}:\/\/([^\/]+)/i);
  174.     if(!parts) return "";
  175.     const host=parts[1];
  176.     var cookie=cookies[host];
  177.     if(cookie) return cookie;
  178.   
  179.     cookie="";
  180.     var iter = this.cookieManager.enumerator;
  181.     var objCookie;
  182.     var cookieHost;
  183.     while (iter.hasMoreElements()){
  184.       objCookie = iter.getNext();
  185.       try {
  186.         if(objCookie instanceof Components.interfaces.nsICookie // implicit QueryInterface()
  187.            && ( host==(cookieHost=objCookie.host) // exact match
  188.                 || ( cookieHost.charAt(0)=='.' && cookieHost==host.substring(host.indexOf('.'))
  189.                       && cookie.indexOf("; "+objCookie.name+"=")==-1 // we don't override subdomain cookies
  190.                     ) // domain match
  191.         )) {
  192.           cookie+="; "+objCookie.name+"="+objCookie.value; // value should be already escaped...
  193.         }
  194.       } catch(ex) {}
  195.     }
  196.     return cookies[host]=cookie?cookie.substring(2):"";
  197.   }
  198. ,
  199.   getPostData: function(l) {
  200.     return "";
  201.   }
  202. ,
  203.   createJobFile: function(job) {
  204.     const jobFile=this.service.tmpDir.clone();
  205.     jobFile.append("flashgot.fgt");
  206.     jobFile.createUnique(0,0700);
  207.     this.service.writeFile(jobFile,job);
  208.     return jobFile;
  209.   }
  210. ,
  211.   performJob: function(job) {
  212.     const jobFile=this.createJobFile(job);
  213.     this.runNative([jobFile.path],false);
  214.   }
  215. ,
  216.   createExecutable: function() {
  217.     const exeFile=this.exeFile;
  218.     if(!exeFile) return false;
  219.     
  220.     const cc=Components.classes;
  221.     const ci=Components.interfaces;
  222.     const ios=cc['@mozilla.org/network/io-service;1'].getService(ci.nsIIOService);
  223.     const bis=cc['@mozilla.org/binaryinputstream;1'].createInstance(ci.nsIBinaryInputStream);
  224.     
  225.     var channel;
  226.     bis.setInputStream((
  227.       channel=
  228.         ios.newChannel("chrome://flashgot/content/"+this.exeName,null,null)
  229.     ).open())
  230.     ;
  231.     const bytesCount=channel.contentLength;
  232.     
  233.     const os=cc["@mozilla.org/network/file-output-stream;1"].createInstance(
  234.       ci.nsIFileOutputStream);
  235.     
  236.     try {
  237.       
  238.       os.init(exeFile,0x02 | 0x08, 0700, 0);
  239.       const bos=cc['@mozilla.org/binaryoutputstream;1'].createInstance(ci.nsIBinaryOutputStream);
  240.       bos.setOutputStream(os);
  241.       bos.writeByteArray(bis.readByteArray(bytesCount),bytesCount);
  242.       bos.close();
  243.  
  244.     } catch(ioErr) { // locked?
  245.       try {
  246.         if(exeFile.exists()) { // security check: it must be the right exe!
  247.           const testBis=cc['@mozilla.org/binaryinputstream;1'].createInstance(
  248.             ci.nsIBinaryInputStream);
  249.           testBis.setInputStream(
  250.             (channel=ios.newChannelFromURI(ios.newFileURI(exeFile))).open());
  251.           const error=new Error("Old, corrupt or unlegitemately modified "
  252.             +exeFile.path
  253.             +".\nThe file is locked: please delete it manually\n");
  254.             +ioErr.message;
  255.           if(channel.contentLength!=bytesCount) throw error;
  256.          
  257.           const legitimateData=bis.readByteArray(bytesCount);
  258.           const testData=testBis.readByteArray(bytesCount);
  259.           for(var j=bytesCount; j-->0;) {
  260.             if(legitimateData[j]!=testData[j]) throw new error;
  261.           }
  262.         } else throw ioErr;
  263.       } catch(unrecoverableErr) {
  264.          this.log("Error creating native executable\n"+exeFile.path+"\n"+unrecoverableErr.message);
  265.       }
  266.     } finally {
  267.       os.close();
  268.       bis.close();
  269.     }
  270.     
  271.     return true;
  272.   }
  273. ,
  274.   runNative: function(args,blocking,exeFile) {
  275.     if(typeof(exeFile)!="object") exeFile=this.exeFile;
  276.     try {
  277.       if(exeFile && exeFile.exists() || this.createExecutable()) {
  278.         const proc=Components.classes['@mozilla.org/process/util;1'].createInstance(
  279.           Components.interfaces.nsIProcess);
  280.         proc.init(exeFile);
  281.         proc.run(blocking,args,args.length,{});
  282.         if(blocking && proc.exitValue!=0) {
  283.           this.log("Warning: native invocation of\n"
  284.             +exeFile.path
  285.             +"\nwith arguments <"
  286.             +args.join(" ")
  287.             +">\nreturned "+proc.exitValue);
  288.         }
  289.         return proc.exitValue;
  290.       }
  291.     } catch(err) {
  292.       this.log("Error running native executable:\n"+exeFile.path+" "+args.join(" ")+"\n"+err.message);
  293.     }  
  294.     return 0xffffffff;
  295.   }
  296. ,
  297.   getWindow: function() {
  298.     return Components.classes["@mozilla.org/appshell/window-mediator;1"
  299.       ].getService(Components.interfaces.nsIWindowMediator).getMostRecentWindow(null)
  300.   }
  301. ,
  302.   selectFolder: function(opType) { 
  303.     const cc=Components.classes;
  304.     const ci=Components.interfaces;
  305.     const downloadDirPref="browser.download.dir";
  306.     const useDownloadDirPref="browser.download.useDownloadDir";
  307.     if(!this.askPath[opType]) return "";
  308.     
  309.     var initialDir;
  310.     const pref = cc["@mozilla.org/preferences-service;1"].getService(ci.nsIPrefBranch);
  311.     try {
  312.       var initialDir = pref.getComplexValue("browser.download.dir", ci.nsILocalFile);
  313.       if(initialDir && pref.getBoolPref(useDownloadDirPref)) {
  314.         return initialDir.path;
  315.       }
  316.     } catch(ex) {}
  317.     
  318.     var title;
  319.     try {
  320.       var bundle = cc["@mozilla.org/intl/stringbundle;1"].getService(ci.nsIStringBundleService);
  321.       bundle = bundle.createBundle("chrome://mozapps/locale/downloads/unknownContentType.properties");
  322.       title = bundle.GetStringFromName("myDownloads");
  323.     } catch(ex) {
  324.       title="Download directory";
  325.     }
  326.     title='FlashGot ('+this.name+') - '+title;
  327.     
  328.    
  329.     const fp = cc["@mozilla.org/filepicker;1"].createInstance(ci.nsIFilePicker);
  330.     const win=this.getWindow();
  331.     fp.init(win, title, ci.nsIFilePicker.modeGetFolder);
  332.     try {
  333.       if (initialDir) {
  334.         fp.displayDirectory = initialDir;
  335.       }
  336.     } catch (ex) { this.log(ex); }
  337.     
  338.     fp.appendFilters(ci.nsIFilePicker.filterAll);
  339.  
  340.     if (fp.show()==ci.nsIFilePicker.returnOK) {
  341.       var localFile = fp.file.QueryInterface(ci.nsILocalFile);
  342.       pref.setComplexValue(downloadDirPref, ci.nsILocalFile, localFile);
  343.       return localFile.path;
  344.     }
  345.     
  346.     throw new Error("Download cancelled by user");
  347.   }
  348.   
  349. }
  350.  
  351. function FlashGotDMX(name) {
  352.   if(arguments.length!=0) {
  353.     this._init(name);
  354.   }
  355. }
  356. FlashGotDMX.prototype=new FlashGotDM();
  357. FlashGotDMX.constructor=FlashGotDMX;
  358. FlashGotDMX._super=FlashGotDM.prototype;
  359. FlashGotDMX.prototype.exeName="flashgot.sh";
  360. FlashGotDMX.prototype.askPath=[true,true,true];
  361.  
  362. function FlashGotDMMac(name, creatorId, macAppName) {
  363.   if(arguments.length!=0) {
  364.     this._init(name);
  365.   }
  366.   const creators=FlashGotDMMac.prototype.macCreators;
  367.   creators[creators.length]={name: name, id: creatorId};
  368.   this.macAppName = macAppName?macAppName:name;
  369. }
  370. FlashGotDMMac.prototype=new FlashGotDM();
  371. FlashGotDMMac.constructor=FlashGotDMMac;
  372. FlashGotDMMac._super=FlashGotDM.prototype;
  373. FlashGotDMMac.prototype.exeName="flashgot-mac.sh";
  374. FlashGotDMMac.prototype.OSASCRIPT="/usr/bin/osascript";
  375. FlashGotDMMac.prototype.macCreators=[];
  376. FlashGotDMMac.prototype.createScriptLauncher=function(scriptPath) {
  377.   return "#!/bin/sh\n"
  378.     +"/usr/bin/osascript '"+scriptPath+"'";
  379. }
  380. FlashGotDMMac.prototype.checkExePlatform=function(exeFile) {
  381.   var f=Components.classes["@mozilla.org/file/local;1"].createInstance(
  382.     Components.interfaces.nsILocalFile);
  383.   try {
  384.     f.initWithPath(this.OSASCRIPT);
  385.     if(f.exists()) return exeFile;
  386.     this.log(f.path+" not found");
  387.   } catch(ex) {
  388.     this.log(ex.message);
  389.   }
  390.   return null;
  391. }
  392. FlashGotDMMac.prototype.createExecutable=function() {
  393.   const exeFile=this.exeFile;
  394.   if( (!exeFile) || exeFile.exists() ) return false;
  395.   try {
  396.    const script=this.service.tmpDir.clone();
  397.    script.append("flashgot-test.scpt");
  398.    FlashGotDMMac.prototype.testAppleScript=script;
  399.    script.createUnique(0,0700);
  400.    if(exeFile.exists()) exeFile.remove(true);
  401.    exeFile.create(0,0700);
  402.    this.service.writeFile(exeFile,this.createScriptLauncher(script.path));
  403.    exeFile.permissions=0700;
  404.   } catch(ex) {
  405.     this.log(ex.message);
  406.   }
  407.   return false;
  408. }
  409. FlashGotDMMac.prototype.launchSupportTest=function(testFile) {
  410.   const creators=FlashGotDMMac.prototype.macCreators;
  411.   const RESP="    do shell script \"echo >>'"+testFile.path+"' '\" & theName & \"|";
  412.   function response(msg) {
  413.     return RESP+msg+"'\"\n";
  414.   }
  415.   var s="on test(theName, theCreator)\n"
  416.        +" tell application \"Finder\"\n"
  417.        +"  try\n"
  418.        +"   if exists application file id theCreator then\n"
  419.        +      response("OK")
  420.        +"   end if\n"
  421.        +"  on error\n"
  422.        +     response("KO")
  423.        +"  end try\n"
  424.        +" end tell\n"
  425.        +"end test\n"
  426.        +"\n";
  427.   for(var j=creators.length; j-->0;) {
  428.      s+='get test("'+creators[j].name+'","'+creators[j].id+'")\n'; 
  429.    }
  430.    this.service.writeFile(this.testAppleScript,s);
  431.    this.runNative([],true,this.exeFile);
  432. }
  433.  
  434. FlashGotDMMac.prototype.performJob=function(job) {
  435.   const script=this.createJobFile(job);
  436.   const launcher=this.createJobFile(this.createScriptLauncher(script.path));
  437.   launcher.permissions=0700;
  438.   this.runNative([],false,launcher);
  439. }
  440.  
  441. FlashGotDMMac.prototype.createJob=function(links,opType) {
  442.   const referrer=this.getReferrer(links);
  443.   var job = "tell application \""+ this.macAppName+ "\"\n";
  444.   for(var j=0,len=links.length; j<len; j++) {
  445.     job+="GetURL \""+links[j].href+"\" from \""+ referrer  +"\"\n";
  446.   }
  447.   job+="end tell\n";
  448.   return job;
  449. }
  450.  
  451.  
  452. FlashGotDM.initDMS=function() {
  453.   var dm;
  454.  
  455.   new FlashGotDM("Download Master");
  456.   
  457.   new FlashGotDM("FlashGet");
  458.   
  459.   new FlashGotDM("Free Download Manager");
  460.   
  461.   dm=new FlashGotDM("GetRight");
  462.   dm.super_createJob=FlashGotDM.prototype.createJob;
  463.   dm.createJob=function(links, opType) {
  464.     const service=this.service;
  465.     const folder=links.folder;
  466.     var referrer;
  467.     switch(opType) {
  468.       case service.OP_ONE:
  469.         return this.super_createJob(links, opType);
  470.       case service.OP_SEL:
  471.       case service.OP_ALL:
  472.         var urlList="";
  473.         var l;
  474.         for(var j=0, len=links.length; j<len; j++) {
  475.           l=links[j];
  476.           urlList+="URL: "+l.href+"\r\nDesc:"+l._description+"\r\n";
  477.           if(folder) {
  478.             var urlParts=l.href.match(/\/([^\/]+?)(\?|\/?$)/);
  479.             if(urlParts) {
  480.               urlList+="File: "+folder+"\\"+decodeURI(urlParts[1])+"\r\n";
  481.             }
  482.           }
  483.         }
  484.         var file=service.tmpDir.clone();
  485.         file.append("flashgot.grx");
  486.         file.createUnique(0,0600);
  487.         service.writeFile(file,urlList);
  488.         referrer=file.path;
  489.         break;
  490.       default:
  491.         referrer=this.getReferrer(links);
  492.     }
  493.     return this.createJobHeader({ length: 0, folder: "" },opType)+referrer+"\n";
  494.   }
  495.   dm.askPath=[false,true,true];
  496.   
  497.   new FlashGotDM("Internet Download Accelerator");
  498.  
  499.   var lg2002=new FlashGotDM("LeechGet 2002");
  500.   lg2002.super_createJob=FlashGotDM.prototype.createJob;
  501.   lg2002.createJob=function(links, opType) {
  502.     const service=this.service;
  503.     var referrer;
  504.     switch(opType) {
  505.       case service.OP_ONE:
  506.         return this.super_createJob(links, opType);
  507.       case service.OP_SEL:
  508.         var htmlDoc="<html><head><title>FlashGot selection</title></head><body>";
  509.         var l;
  510.         for(var j=0, len=links.length; j<len; j++) {
  511.           l=links[j];
  512.           var des=l._description;
  513.           var tag=l.tagName?l.tagName.toUpperCase():"";
  514.           htmlDoc=htmlDoc.concat(tag=="IMG"
  515.             ?"<img src=\""+l.href+"\" alt=\""+des
  516.               +"\" width=\""+l.width+"\" height=\""+l.height+
  517.               "\" />\n"
  518.             :"<a href=\""+l.href+"\">"+des+"</a>\n");
  519.         }
  520.         referrer=service.httpServer.addDoc(
  521.           htmlDoc.concat("</body></html>")
  522.         );
  523.         break;
  524.        default:
  525.         referrer=this.getReferrer(links);
  526.     }
  527.     return this.createJobHeader({ length: 0, folder: "" },opType)+referrer+"\n";
  528.   }
  529.   
  530.   var lg2004=new FlashGotDM("LeechGet 2004");
  531.   lg2004.super_createJob=lg2002.super_createJob;
  532.   lg2004.createJob=lg2002.createJob;
  533.   
  534.   new FlashGotDM("Net Transport");
  535.   
  536.   new FlashGotDM("ReGet Deluxe");
  537.   new FlashGotDM("ReGet Junior"); 
  538.   new FlashGotDM("ReGet Pro"); 
  539.   
  540.   new FlashGotDMX("Aria");
  541.   new FlashGotDMX("Downloader 4 X");
  542.   
  543.   dm=new FlashGotDMMac("Speed Download 2","Spee");
  544.   dm.createJob=function(links,opType) {
  545.     var job = "tell application \""+ this.macAppName+ "\"\n";
  546.     job+="AddURL {";
  547.     for(var j=0,len=links.length; j<len; j++) {
  548.       if(j>0) job+=',';
  549.       job+='"'+links[j].href+'"';
  550.     }
  551.     job+="}\nend tell\n";
  552.     return job;
  553.   }
  554.   
  555.   new FlashGotDMMac("iGetter","iGET");
  556.   
  557.   FlashGotDM.dms.sort(function(a,b) { a=a.name.toUpperCase(); b=b.name.toUpperCase(); return a==b?0:a<b?-1:1; });
  558.   
  559.   
  560. };
  561. FlashGotDM.initDMS();
  562.  
  563.  
  564. const SHUTDOWN="profile-before-change";
  565. const STARTUP="profile-after-change";
  566.  
  567. /* interfaces implemented by this component */
  568. const FLASHGOT_SERVICE_IIDS = 
  569. // Components.interfaces.IFlashGotService,
  570. Components.interfaces.nsIObserver,
  571. Components.interfaces.nsISupports,
  572. ];
  573.  
  574. /* components defined in this file */
  575.  
  576. const FLASHGOT_SERVICE_CID =
  577.     Components.ID("{2a55fc5c-7b31-4ee1-ab15-5ee2eb428cbe}");
  578. const FLASHGOT_SERVICE_CTRID =
  579.     "@informaction.org/flashgot-service;1";
  580.  
  581. /* components used by this file */
  582. const CATMAN_CTRID = "@mozilla.org/categorymanager;1";
  583.  
  584.  
  585. function flashgot_checkInterfaces(iid,ex) {
  586.   for(var j=FLASHGOT_SERVICE_IIDS.length; j-- >0;) {
  587.     if(iid.equals(FLASHGOT_SERVICE_IIDS[j])) return true;
  588.   }
  589.   throw ex;
  590. }
  591.  
  592. /* factory for FlashGotService  */
  593. var FlashGotServiceFactory = new Object();
  594.  
  595. FlashGotServiceFactory.createInstance = function (outer, iid) {
  596.     if (outer != null)
  597.         throw Components.results.NS_ERROR_NO_AGGREGATION;
  598.  
  599.     flashgot_checkInterfaces(iid,Components.results.NS_ERROR_INVALID_ARG);
  600.  
  601.     return new FlashGotService();
  602. }
  603.  
  604. function FlashGotService() {
  605.   this.wrappedJSObject=this;
  606.   this._globals=null;
  607.   
  608.   const osvr=Components.classes['@mozilla.org/observer-service;1'].getService(
  609.     Components.interfaces.nsIObserverService);
  610.   
  611.   osvr.addObserver(this,SHUTDOWN,false);
  612.   osvr.addObserver(this,"xpcom-shutdown",false);
  613.   osvr.addObserver(this,STARTUP,false);
  614. }
  615.  
  616. FlashGotService.prototype = {
  617.   OP_ONE: 0, 
  618.   OP_SEL: 1,
  619.   OP_ALL: 2
  620. ,
  621.   unregister: function() {
  622.     try {
  623.       const osvr=Components.classes['@mozilla.org/observer-service;1'].getService(
  624.       Components.interfaces.nsIObserverService);
  625.       osvr.removeObserver(this,SHUTDOWN);
  626.       osvr.removeObserver(this,"xpcom-shutdown");
  627.       osvr.removeObserver(this,STARTUP);
  628.     } catch(ex) {
  629.       this.log("Error unregistering service as observer: "+ex);
  630.     }
  631.   }
  632. ,
  633.   QueryInterface: function(iid) {
  634.      flashgot_checkInterfaces(iid,Components.results.NS_ERROR_NO_INTERFACE);
  635.      return this;
  636.   }
  637. ,
  638.   /* nsIObserver */  
  639.   observe: function(subject, topic, data) {
  640.     this.log(topic,data);
  641.     switch(topic) {
  642.       case "xpcom-shutdown":
  643.         this.unregister();
  644.       case SHUTDOWN: 
  645.         this.cleanup();
  646.         break;
  647.       case STARTUP:
  648.         this.initGlobals();
  649.         break;
  650.     }
  651.   }
  652. ,
  653.   get defaultDM() {
  654.     return this.getPref("defaultDM");
  655.   }
  656. ,
  657.   set defaultDM(name) {
  658.     this.setPref("defaultDM", name);
  659.     return name;
  660.   }
  661. ,
  662.   get tmpDir() {
  663.     return this.globals.tmpDir; 
  664.   }
  665. ,
  666.   get profDir() {
  667.     return this.globals.profDir; 
  668.   }
  669. ,
  670.   get DMS() {
  671.     return this.globals.DMS;
  672.   }
  673. ,
  674.   get httpServer() {
  675.     return (!this._httpServer) || this._httpServer.isDown
  676.       ?this._httpServer=new FlashGotHttpServer(this)
  677.       :this._httpServer;
  678.   }
  679.  
  680. ,
  681.   download: function(links, opType, dmName) {
  682.     if(links.length==0) return;
  683.     if(!opType) opType=links.length>1?this.OP_SEL:this.OP_ONE;
  684.     if(!dmName) dmName=this.defaultDM;
  685.     var dm=this.globals.DMS[dmName];
  686.     if(!dm) {
  687.       this.log("FlashGot error: no download manager selected!");
  688.       return;
  689.     }
  690.     // urlescaped purification patch, thank to Matt Mees for suggestion
  691.     function parseDesc(link) {
  692.       return link._description?link._description
  693.         :link._description = (typeof(link.title)=="string" && link.title.length>0
  694.             ?link.title:link.innerHTML).replace(
  695.                 /<.*?>/g,"").replace(/\s+/g," ");
  696.     }
  697.     
  698.     function killDuplicates(links, start) {
  699.       var l=links[start];
  700.       var href=l.href;
  701.       var descLen=parseDesc(l).length;
  702.       var l2;
  703.       for(var k=start; k-->0;) {
  704.         l2=links[k];
  705.         if(href==l2.href) {
  706.           if(descLen<=parseDesc(l2).length) {
  707.             links.splice(j,1);
  708.             return null;
  709.           } else {
  710.             links.splice(k,1);
  711.             j--;
  712.           }
  713.         }
  714.       }
  715.       return l;
  716.     }
  717.     
  718.     var l;
  719.     for(var j=links.length; j-- >0; ) {
  720.       if(!(l=killDuplicates(links,j))) continue;
  721.       
  722.       urlParts=l.href.split("?");
  723.       try {
  724.         urlParts[0]=decodeURI(urlParts[0]);
  725.         l.href=urlParts.join("?");
  726.       } catch(e) {
  727.         this.log("Error decoding URI "+l.href+"\n"+e.message);
  728.       }
  729.     }
  730.     
  731.     
  732.     dm.download(links,opType);
  733.   }
  734. ,
  735.   get prefService() {
  736.     return Components.classes["@mozilla.org/preferences-service;1"].getService(
  737.       Components.interfaces.nsIPrefService);
  738.   }
  739. ,
  740.   getPref: function(name,def) {
  741.     const IPC=Components.interfaces.nsIPrefBranch;
  742.     const prefs=this.globals.prefs;
  743.     try {
  744.       switch(prefs.getPrefType(name)) {
  745.         case IPC.PREF_STRING:
  746.           return prefs.getCharPref(name);
  747.         case IPC.PREF_INT:
  748.           return prefs.getIntPref(name);
  749.         case IPC.PREF_BOOL:
  750.           return prefs.getBoolPref(name);
  751.       }
  752.     } catch(e) {}
  753.     return def;
  754.   }
  755. ,
  756.   setPref: function(name,value) {
  757.     const prefs=this.globals.prefs;
  758.     switch(typeof(value)) {
  759.       case "string":
  760.           prefs.setCharPref(name,value);
  761.           break;
  762.       case "boolean":
  763.         prefs.setBoolPref(name,value);
  764.         break;
  765.       case "number":
  766.         prefs.setIntPref(name,value);
  767.         break;
  768.       default:
  769.         throw new Error("Unsupported type "+typeof(value)+" for preference "+name);
  770.     }
  771.   }
  772.   
  773. ,
  774.   log: function(msg) {
  775.     try {
  776.       if(!this.rootWindow) {
  777.         this.rootWindow=Components.classes['@mozilla.org/appshell/appShellService;1'
  778.           ].getService(Components.interfaces.nsIAppShellService).hiddenDOMWindow;
  779.       }
  780.       this.rootWindow.dump("<FLASHGOT>\n"+msg+"\n</FLASHGOT>\n");
  781.     } catch(ex) {}
  782.   }
  783. ,
  784.   checkLink: function(link) {
  785.     return link && link.href && /^[a-z]+:\/\/.*/i.test(link.href) && ! /^(javascript|mailto|news|file):/i.test(link.href);
  786.   }
  787. ,
  788.   checkAnchor: function(elem) {
  789.     return elem instanceof Components.interfaces.nsIDOMHTMLAnchorElement
  790.       && elem.href;
  791.   }
  792. ,
  793.   findLinkAsc: function(node) {
  794.      while(node) {
  795.       if(this.checkAnchor(node))
  796.         return this.checkLink(node)?node:null;
  797.       node = node.parentNode;
  798.     }
  799.     return null;
  800.   }
  801. ,
  802.   checkLocale: function() {
  803.     if(typeof(this._checkedLocale)=="undefined") {
  804.       try {
  805.        this._checkedLocale=(new IA_LocaleChecker("flashgot")).check();
  806.       } catch(ex) {
  807.         this.log("Locale check failed: "+ex);
  808.         this._checkedLocale=null;
  809.       }
  810.     }
  811.     return this._checkedLocale;
  812.   }
  813. ,
  814.   get globals() {
  815.     return this._globals?this._globals:this._globals=this.initGlobals();
  816.   }
  817. ,
  818.   initCount: 0, 
  819.   initOKCount: 0,
  820.   initGlobals: function() {
  821.     this.initCount++;
  822.     this.rootWindow=null;
  823.     
  824.     const cc=Components.classes;
  825.     const ci=Components.interfaces; 
  826.     
  827.     this.prefService.getBranch("browser.dom.window.dump.").setBoolPref("enabled",true);
  828.     
  829.     this.log("Per-session init started");
  830.     this.log("Checked locale: "+this.checkLocale());
  831.     
  832.     const fileLocator=cc["@mozilla.org/file/directory_service;1"].getService(
  833.       ci.nsIProperties);
  834.     const tmpDir=fileLocator.get("TmpD",ci.nsIFile);
  835.     const profDir=fileLocator.get("ProfD",ci.nsIFile);
  836.      
  837.     tmpDir.append("flashgot");
  838.     tmpDir.createUnique(1,0700);
  839.     
  840.     this._globals={
  841.       tmpDir: tmpDir,
  842.       profDir: profDir,
  843.       prefs: this.prefService.getBranch("flashgot.")
  844.     };
  845.     
  846.     this.setupLegacyPrefs();
  847.    
  848.     this._globals.DMS=this.checkDownloadManagers(),
  849.    
  850.     this.log("Per-session init done");
  851.     
  852.     this.initOKCount++;
  853.     return this._globals;
  854.   }
  855. ,
  856.   checkDownloadManagers: function() {
  857.     
  858.     const dms=FlashGotDM.dms;
  859.     dms.found=false;
  860.     
  861.     
  862.     var defaultDM=this.defaultDM;
  863.     if(!dms[defaultDM]) defaultDM=null;
  864.     var firstSupported=null;
  865.     var dm;
  866.     for(var j=dms.length; j-- >0;) {
  867.       dm=dms[j];
  868.       if(dm.supported ) {
  869.         dms.found=true;
  870.         firstSupported=dm.name;
  871.       } else {
  872.         this.log("Warning: download manager "+dm.name+" not found");
  873.         if(defaultDM==dm.name) {
  874.           defaultDM=null;
  875.           this.log(dm.name+" was default download manager: resetting.");
  876.         }
  877.       }
  878.     }
  879.     
  880.     if( (!defaultDM) && firstSupported!=null) {
  881.       this.defaultDM=firstSupported;
  882.       this.log("Default download manager set to "+this.defaultDM);
  883.     } else if(!dms.found) {
  884.       this.log("Serious warning! no supported download manager found...");
  885.     }
  886.     
  887.     return dms;
  888.   }
  889.   cleanup: function() {
  890.     try {
  891.       if(this._httpServer) {
  892.         this._httpServer.shutdown();
  893.       }
  894.       if(this._globals && this._globals.tmpDir.exists()) {
  895.         this._globals.tmpDir.remove(true);
  896.       }
  897.     } catch(ex) {
  898.        this.log(ex);
  899.     }
  900.   }
  901. ,
  902.   readFile: function(file) {
  903.     const cc=Components.classes;
  904.     const ci=Components.interfaces; 
  905.     
  906.     var is = cc["@mozilla.org/network/file-input-stream;1"].createInstance(
  907.           ci.nsIFileInputStream );
  908.     is.init(file ,0x01, 0400, null);
  909.     var sis = cc["@mozilla.org/scriptableinputstream;1"].createInstance(
  910.       ci.nsIScriptableInputStream );
  911.     sis.init( is );
  912.     var res=sis.read( sis.available() );
  913.     is.close();
  914.     return res;
  915.   }
  916. ,
  917.   writeFile: function(file, content) {
  918.     const cc=Components.classes;
  919.     const ci=Components.interfaces;
  920.     const unicodeConverter = cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(
  921.     ci.nsIScriptableUnicodeConverter);
  922.     unicodeConverter.charset = "UTF-8";
  923.     content=unicodeConverter.ConvertFromUnicode(content);
  924.     const os=cc["@mozilla.org/network/file-output-stream;1"].createInstance(
  925.       ci.nsIFileOutputStream);
  926.     os.init(file,0x02,0700,0);
  927.     os.write(content,content.length);
  928.     os.close();
  929.   }
  930. ,
  931.   setupLegacyPrefs: function() {
  932.     try {
  933.       var file=this.globals.profDir.clone();
  934.       file.append("pref");
  935.       file.append("flashgot.js");
  936.       if(file.exists()) {
  937.         this.prefService.readUserPrefs(file);
  938.       }
  939.     } catch(e) {
  940.       this.log(e.message);
  941.     }
  942.   }
  943. ,
  944. _dirtyJobsDone: false,
  945. doDirtyJobs: function() {
  946.     if(this._dirtyJobsDone) {
  947.       return; 
  948.     }
  949.     const cc=Components.classes;
  950.     const ci=Components.interfaces;
  951.     const locator = cc["@mozilla.org/file/directory_service;1"].getService(ci.nsIProperties);
  952.     const chromeDirs=[locator.get("AChrom", ci.nsIFile).path,
  953.       locator.get("UChrm", ci.nsIFile).path];
  954.     const rdf = cc["@mozilla.org/rdf/rdf-service;1"].getService(ci.nsIRDFService);
  955.     const rdfUtil  = cc["@mozilla.org/rdf/container-utils;1"].getService(ci.nsIRDFContainerUtils);
  956.     const overlays=new Object();
  957.     overlays['browser']
  958.     =overlays['navigator']  
  959.       =["chrome://flashgot/localeCheckOverlay.xul"];
  960.     
  961.     var url, ds, overlayName, overlay, literal, res, src;
  962.     for(var j = 0; j < chromeDirs.length; j++) { // Application & Profile Dirs
  963.       // Loop files
  964.       var overlayDir=chromeDirs[j].replace(/\\/g,'/')+'/overlayinfo/';
  965.       for(overlayName in overlays){
  966.         try{
  967.           url="file:///"+ overlayDir +overlayName+ '/content/overlays.rdf';
  968.           ds = rdf.GetDataSourceBlocking(url).QueryInterface(ci.nsIRDFRemoteDataSource);
  969.           // Loop overlay elements for this file
  970.           var overlay=overlays[overlayName];
  971.           for(var i = 0; i < overlay.length; i++){
  972.             var literal=rdf.GetLiteral(overlay[i]);
  973.             // Find Element
  974.             var archs = ds.ArcLabelsIn(literal);
  975.             while(archs.hasMoreElements()){
  976.               var res = archs.getNext().QueryInterface(ci.nsIRDFResource);
  977.               var sources = ds.GetSources(res, literal, true);
  978.               
  979.               // Get parent element for element
  980.               while(sources.hasMoreElements()){
  981.                 src = sources.getNext().QueryInterface(ci.nsIRDFResource);
  982.                 
  983.                 try {
  984.                     ds.Unassert(src, res, literal);
  985.                     this.log("Removed "+ literal.Value +" from "+url);
  986.                 } catch(ex) {
  987.                     this.log("Failed to remove "+ listeral.Value +" from "+url);
  988.                     this.log(ex.message);
  989.                 }
  990.               }
  991.             }
  992.           }
  993.           
  994.           ds.Flush();
  995.           this.log("Cleaned "+url);
  996.          } catch(ex) {
  997.             this.log("Failed to clean "+url);
  998.             this.log(ex.message);
  999.          }
  1000.       }
  1001.     }
  1002.     this._dirtyJobsDone=true;
  1003.   }
  1004. }
  1005.  
  1006. var Module = new Object();
  1007. Module.firstTime=true;
  1008. Module.registerSelf = function (compMgr, fileSpec, location, type) {
  1009.   if(this.firstTime) {
  1010.    
  1011.     debug("*** Registering FlashGot service.\n");
  1012.     
  1013.     compMgr =
  1014.         compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  1015.   
  1016.     compMgr.registerFactoryLocation(FLASHGOT_SERVICE_CID,
  1017.       "FlashGot Service",
  1018.       FLASHGOT_SERVICE_CTRID, 
  1019.       fileSpec,
  1020.       location, 
  1021.       type);
  1022.    /*
  1023.     Components.classes[FLASHGOT_SERVICE_CTRID].getService(
  1024.       Components.interfaces.nsISupports);
  1025.   */ //CHECK ME
  1026.     this.firstTime=false;
  1027.   } 
  1028.   
  1029.   
  1030. }
  1031. Module.unregisterSelf =
  1032. function(compMgr, fileSpec, location)
  1033. {
  1034.   
  1035.   compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  1036.   
  1037.   compMgr.unregisterFactoryLocation(FLASHGOT_SERVICE_CID, fileSpec);
  1038.   
  1039. }
  1040.  
  1041. Module.getClassObject = function (compMgr, cid, iid) {
  1042.   if (cid.equals(FLASHGOT_SERVICE_CID))
  1043.     return FlashGotServiceFactory;
  1044.  
  1045.   if (!iid.equals(Components.interfaces.nsIFactory))
  1046.     throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  1047.   
  1048.   throw Components.results.NS_ERROR_NO_INTERFACE;
  1049.     
  1050. }
  1051.  
  1052. Module.canUnload = function(compMgr) {
  1053.   return true;
  1054. }
  1055.  
  1056. /* entrypoint */
  1057. function NSGetModule(compMgr, fileSpec) {
  1058.   return Module;
  1059. }
  1060.  
  1061. /* Data Swap HTTP server */
  1062.  
  1063. FlashGotHttpServer=function(fgService) {
  1064.   this.fgService=fgService;
  1065.   this.isDown=true;
  1066.   this.serverSocket=Components.classes['@mozilla.org/network/server-socket;1'
  1067.     ].createInstance(Components.interfaces.nsIServerSocket);
  1068.   this.serverSocket.init(-1,true,-1);
  1069.   this.isDown=false;
  1070.   this.serverSocket.asyncListen(this);
  1071.   this.tmpDir=this.fgService.globals.tmpDir.clone();
  1072.   this.tmpDir.append("httpserv");
  1073.   this.log("Listening");
  1074. }
  1075.  
  1076. FlashGotHttpServer.prototype={
  1077.   documents: []
  1078. ,
  1079.   log: function(msg){
  1080.     try {
  1081.       if(!this.logStream) {
  1082.         logFile=this.tmpDir.clone();
  1083.         logFile.append("server.log");
  1084.         logFile.createUnique(0,0600);
  1085.         this.logStream=Components.classes["@mozilla.org/network/file-output-stream;1"
  1086.           ].createInstance(Components.interfaces.nsIFileOutputStream );
  1087.         this.logStream.init(logFile, 0x02 | 0x10, 0600, 0 );
  1088.       }
  1089.       msg="HttpServer:"+this.serverSocket.port+" - "+msg+"\n";
  1090.       this.logStream.write(msg,msg.length);
  1091.       this.logStream.flush();
  1092.     } catch(ex) {}
  1093.     
  1094.   }
  1095. ,
  1096.   onSocketAccepted: function(ss,transport) {
  1097.     this.log("Accepted request from "
  1098.       +transport.host+":"+transport.port);
  1099.      try {
  1100.         new FlashGotHttpHandler(this,transport);
  1101.      } catch(ex) {
  1102.        this.log(ex.message);
  1103.      }
  1104.   }
  1105. ,
  1106.   onStopListening: function(ss,status) {
  1107.     this.isDown=true;
  1108.     if(this.logStream) {
  1109.       this.log("Stopped, status "+status);
  1110.     }
  1111.   }
  1112. ,
  1113.   randomName: function(len) {
  1114.     if(!len) len=8;
  1115.     var name="";
  1116.     for(var j=len; j-->0;) {
  1117.       name+=String.fromCharCode(65+(Math.round(Math.random()*25)));
  1118.     }
  1119.     return name;
  1120.   }
  1121. ,
  1122.   addDoc: function(docSource,docType) {
  1123.     if(typeof(docType)=="undefined") docType="html";
  1124.     var file=this.tmpDir.clone();
  1125.     file.append(this.randomName()+"."+docType);
  1126.     file.createUnique(0,0600);
  1127.     this.fgService.writeFile(file,docSource);
  1128.     const name=file.leafName;
  1129.     this.documents.push(name);
  1130.     return "http://localhost:"+this.serverSocket.port+"/"+name;
  1131.   }
  1132. ,
  1133.   getDoc: function(name) {
  1134.     const docs=this.documents;
  1135.     for(var j=docs.length; j-->0;) {
  1136.       if(docs[j]==name) break;
  1137.     }
  1138.     if(j<0) return null;
  1139.     var file=this.tmpDir.clone();
  1140.     file.append(name);
  1141.     return file.exists()?this.fgService.readFile(file):null;
  1142.   }
  1143. ,  
  1144.   shutdown: function() {
  1145.     try {
  1146.       this.log("Shutting down");
  1147.       if(this.logStream) {
  1148.         this.logStream.close();
  1149.         this.logStream=null;
  1150.       }
  1151.       this.serverSocket.close();
  1152.     } catch(ex) {}
  1153.   }
  1154. }
  1155.  
  1156. function FlashGotHttpHandler(server,transport) {
  1157.   this.server=server;
  1158.   this.inputBuffer="";
  1159.   this.transport=transport;
  1160.   this.asyncStream=transport.openInputStream(0,0,0).QueryInterface(
  1161.     Components.interfaces.nsIAsyncInputStream);
  1162.   this.log("Waiting for request data...");
  1163.   
  1164.   const nsIThread=Components.interfaces.nsIThread;
  1165.   var thread=Components.classes['@mozilla.org/thread;1'].createInstance(nsIThread);
  1166.   thread.init(this, 0,  nsIThread.PRIORITY_NORMAL, nsIThread.SCOPE_GLOBAL,nsIThread.STATE_JOINABLE);
  1167.   this.log("Thread started");
  1168. }
  1169.  
  1170. FlashGotHttpHandler.prototype = {
  1171.   log: function(msg) {
  1172.     this.server.log(this.transport.host+":"+this.transport.port+" - "+msg);
  1173.   }
  1174. ,
  1175.   run: function() {
  1176.      this.log("I'm in thread");
  1177.      this.asyncStream.asyncWait(this,0,0,null);
  1178.      this.log("Asyncwait issued");
  1179.   }
  1180. ,  
  1181.   onInputStreamReady: function(asyncStream) {
  1182.     const bytesCount=asyncStream.available();
  1183.     this.log("Input stream ready, available bytes: "+bytesCount);
  1184.     if(bytesCount) {
  1185.       const inStream=Components.classes['@mozilla.org/scriptableinputstream;1'].createInstance(
  1186.         Components.interfaces.nsIScriptableInputStream);
  1187.       inStream.init(asyncStream);
  1188.       var chunk=inStream.read(inStream.available());
  1189.       this.log("Received data chunk "+chunk);
  1190.       var buffer=this.inputBuffer.concat(chunk);
  1191.       var eor=chunk.length==0?buffer.length:buffer.search("\r?\n\r?\n");
  1192.       this.log("EOR: "+eor);
  1193.       if(eor>-1) {
  1194.         var request=buffer.substring(0,eor);
  1195.         this.inputBuffer="";
  1196.         this.handleRequest(request);
  1197.         this.close();
  1198.       } else {
  1199.         this.inputBuffer=buffer;
  1200.         this.run();
  1201.       }
  1202.     } else {
  1203.       this.close();
  1204.     }
  1205.   }
  1206. ,
  1207.   close: function() {
  1208.     this.asyncStream.close();
  1209.   }
  1210. ,
  1211.   buildResponse: function(body,status,contentType) {
  1212.     if(!contentType) contentType="text/html";
  1213.     if(!status) {
  1214.       status="200 OK";
  1215.     } else {
  1216.       body="<h1>"+status+"</h1><pre>"
  1217.         +body
  1218.         +"</pre><h5>FlashGot Http Server v. 0.1</h5>"
  1219.     }
  1220.     return "HTTP/1.1 "+status+"\r\nContent-type: "+contentType+"\r\n\r\n"+body;
  1221.   }
  1222. ,
  1223.   handleRequest: function(request) {
  1224.     var response;
  1225.     var match;
  1226.     this.log("Handling request\n"+request);
  1227.     try {
  1228.       if(!(match=request.match(/^GET \/([^\s]*)/))) {
  1229.         response=this.buildResponse(request,"400 Bad Request"); 
  1230.       } else {
  1231.         var doc=this.server.getDoc(match[1]);
  1232.         
  1233.         if(doc==null) {
  1234.           response=this.buildResponse(request,"404 Not Found");
  1235.         } else {
  1236.           response=this.buildResponse(doc);
  1237.         }
  1238.       }
  1239.     } catch(ex) {
  1240.       response=this.buildResponse(ex.message+"\n"+request,"500 Server error");
  1241.     }
  1242.     var out=this.transport.openOutputStream(1,0,0);
  1243.     out.write(response,response.length);
  1244.     out.close();
  1245.     this.log("Sent response\n"+response);
  1246.   } 
  1247. }
  1248.  
  1249.  
  1250. /* Locale check */
  1251. IA_LocaleChecker=function(module) {  
  1252.   this.module=module;
  1253. }
  1254.  
  1255. IA_LocaleChecker.prototype = {
  1256.  
  1257.   check: function() {
  1258.     const module=this.module;
  1259.     const cc=Components.classes;
  1260.     const ci=Components.interfaces;
  1261.  
  1262.     const localeURL="chrome://"+module+"/locale";
  1263.     
  1264.     try {
  1265.       const window=cc['@mozilla.org/appshell/appShellService;1'
  1266.             ].getService(ci.nsIAppShellService
  1267.         ).hiddenDOMWindow
  1268.     } catch(ex) {}
  1269.     
  1270.     function log(msg) {
  1271.       if(window) window.dump("LocaleChecker: "+msg+"\n");
  1272.     }
  1273.   
  1274.     function checkLocale(locale) {
  1275.       function isLocaleSelected() {
  1276.         try {
  1277.           return chreg.getSelectedLocale(module)==locale;
  1278.         } catch(ex) {
  1279.           log(ex.message);
  1280.           return false;
  1281.         }
  1282.       }
  1283.       
  1284.       try {
  1285.         if(!isLocaleSelected()) {
  1286.           log("trying to select locale "+locale);
  1287.           chreg.selectLocaleForPackage(locale,module,true);
  1288.           if(isLocaleSelected()) {
  1289.             
  1290.             for(var j=2; j-->0;) {
  1291.               chreg.checkForNewChrome();
  1292.               chreg.reloadChrome();
  1293.               log("chrome reloaded! "+j);
  1294.             }
  1295.             
  1296.           } else {
  1297.             log("Can't select locale "+locale+" for "+module); 
  1298.             locale=null;
  1299.           }
  1300.         }
  1301.       } catch(ex) {
  1302.         log("Error checking/setting locale "+locale+" for "+module+"\n"+ex.message);
  1303.         locale=null;
  1304.       }
  1305.       return locale;
  1306.     }
  1307.      
  1308.     var chreg=cc["@mozilla.org/chrome/chrome-registry;1"].getService(ci.nsIXULChromeRegistry);
  1309.    
  1310.     var browserLocale=null;
  1311.     try {
  1312.       browserLocale=chreg.getSelectedLocale("browser",true);
  1313.     } catch(ex1) {
  1314.       log("It seems no locale is selected for browser... trying with navigator");
  1315.       try {
  1316.         browserLocale=chreg.getSelectedLocale("navigator",true);
  1317.       } catch(ex2) {
  1318.         log("It seems no locale is selected for navigator...");
  1319.       }
  1320.     }
  1321.     var ret=null;
  1322.     if(browserLocale==null
  1323.       || !(ret=checkLocale(browserLocale))) {
  1324.         ret=checkLocale("en-US");
  1325.     }
  1326.     return ret;
  1327.   }
  1328. }
  1329.  
  1330.